#include "utils/socket.h"
#include <iostream>
#include <vector>
#include <memory>

using namespace cox;

void testUdpMultiPortServer() {
	// 1. 创建两个UDP套接字，分别监听7001和7002端口
	std::vector<std::unique_ptr<Socket>> udpSockets;
	std::vector<unsigned short>          ports = {7001, 7002};

	for (auto port: ports) {
		// 创建UDP套接字
		std::unique_ptr<Socket> sock(new Socket(Socket::UDP));
		if (!sock->isValid()) {
			std::cerr << "创建UDP套接字（端口" << port << "）失败，错误码：" << sock->getError() << std::endl;
			return;
		}

		// 设置地址复用（避免端口占用问题）
		if (!sock->setReuseAddr(true)) {
			std::cerr << "UDP端口" << port << "设置地址复用失败" << std::endl;
			return;
		}

		// 绑定到指定端口（0.0.0.0表示监听所有网络接口）
		NetAddr addr("0.0.0.0", port);
		if (!sock->bind(addr)) {
			std::cerr << "UDP端口" << port << "绑定失败，错误码：" << sock->getError() << std::endl;
			return;
		}

		std::cout << "SELECT多路复用，监听 " << addr.host << ":" << addr.port << std::endl;
		udpSockets.push_back(std::move(sock));
	}

	// 2. 准备select监控列表
	std::vector<Socket *> readVec;

	while (true) {
		// 每次循环前重新添加需要监控的套接字
		readVec.clear();
		for (const auto &sock: udpSockets) {
			readVec.push_back(sock.get());
		}

		// 等待可读事件（超时1秒，避免永久阻塞）
		int ret = Socket::select(&readVec, nullptr, nullptr, TimeVal(1, 0));
		if (ret < 0) {
			std::cerr << "select错误，错误码：" << SOCKETERR() << std::endl;
			break;
		} else if (ret == 0) {
			continue; // 超时，继续下一次循环
		}

		// 3. 处理就绪的UDP套接字
		for (Socket *sock: readVec) {
			char      buf[1024] = {0};
			NetAddr   senderAddr; // 发送方地址
			long long recvLen = sock->recvfrom(buf, 1023, senderAddr);

			if (recvLen > 0) {
				// 输出接收信息（包含端口区分）
				std::cout << "收到数据（端口" << sock->getAddr().port << "，来自" << senderAddr.host << ":" << senderAddr.port << "）：" << buf << std::endl;

				// 可选：回复发送方（回声功能）
				std::string reply = "已收到：" + std::string(buf);
				sock->sendto(reply.c_str(), reply.size(), senderAddr);
			} else if (recvLen < 0) {
				std::cerr << "端口" << sock->getAddr().port << "接收失败，错误码：" << sock->getError() << std::endl;
			}
		}
	}
}

// 编译：g++ -std=c++11 -o select_udp select_udp.cpp SocketAdapter.cpp TimeAdapter.cpp
// # 向7001端口发送数据
// echo "测试Select_UDP1" | nc -u -w 1 127.0.0.1 7001
// # 向7002端口发送数据
// echo "测试Select_UDP2" | nc -u -w 1 127.0.0.1 7002
int main() {
	testUdpMultiPortServer();
	return 0;
}
